﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DoeObjects;
using System.Collections.Generic;

namespace DoeLibsTest
{
    [TestClass]
    public class Loan_Tests
    {

        [TestInitialize]
        public void initializeDatabaseConnection()
        {
            TestContext.initialize();
        }

        [TestMethod]
        public void getExpiredLoans_Test_AllLoansExpired()
        {

            //TestContext.clearDatabase();

            Helper.clearLoanTable();

            User u1 = Helper.createUserObject(false, true);
            Loan l1_1 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_1);
            l1_1.save();
            Loan l1_2 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_2);
            l1_2.save();

            User u2 = Helper.createUserObject(false, true);
            Loan l2_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_1);
            l2_1.save();
            Loan l2_2 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_2);
            l2_2.save();
            Loan l2_3 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_3);
            l2_3.save();

            User u3 = Helper.createUserObject(false, true);
            Loan l3_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l3_1);
            l3_1.save();

            List<Loan> ExpiredLoans = Loan.getExpiredLoans();

            Assert.AreEqual(6, ExpiredLoans.Count);//Shows we get the right number back

            //Checks if the right loan IDs were returned
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l1_1.LoanId));
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l1_2.LoanId));
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l2_1.LoanId));
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l2_2.LoanId));
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l2_3.LoanId));
            Assert.IsTrue(ExpiredLoans.Exists(item => item.LoanId == l3_1.LoanId));
            
        }

        [TestMethod]
        public void handleExpiredLoans_Test_AllLoansExpired_NoReservations()
        {
            Helper.clearLoanTable();

            User u1 = Helper.createUserObject(false, true);
            Loan l1_1 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_1);
            l1_1.save();
            Loan l1_2 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_2);
            l1_2.save();

            User u2 = Helper.createUserObject(false, true);
            Loan l2_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_1);
            l2_1.save();
            Loan l2_2 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_2);
            l2_2.save();
            Loan l2_3 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_3);
            l2_3.save();

            User u3 = Helper.createUserObject(false, true);
            Loan l3_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l3_1);
            l3_1.save();

            Loan.handleExpiredLoans();

            Assert.AreEqual(2, Notification.getAllForUser(u1.UserId).Count);
            l1_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l1_1.ToBeReturnedDate,Loan.getLoan(l1_1.LoanId).ToBeReturnedDate);
            l1_2.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l1_2.ToBeReturnedDate, Loan.getLoan(l1_2.LoanId).ToBeReturnedDate);

            Assert.AreEqual(3, Notification.getAllForUser(u2.UserId).Count);
            l2_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_1.ToBeReturnedDate, Loan.getLoan(l2_1.LoanId).ToBeReturnedDate);
            l2_2.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_2.ToBeReturnedDate, Loan.getLoan(l2_2.LoanId).ToBeReturnedDate);
            l2_3.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_3.ToBeReturnedDate, Loan.getLoan(l2_3.LoanId).ToBeReturnedDate);

            Assert.AreEqual(1, Notification.getAllForUser(u3.UserId).Count);
            l3_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l3_1.ToBeReturnedDate, Loan.getLoan(l3_1.LoanId).ToBeReturnedDate);

        }

        [TestMethod]
        public void handleExpiredLoans_Test_AllLoansExpired_SomeReservations()
        {
            Helper.clearLoanTable();
            Helper.clearReservationsTable();

            User ur = Helper.createUserObject(false, true);

            User u1 = Helper.createUserObject(false, true);
            Loan l1_1 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_1);
            l1_1.save();
            Reservation.createReservation(l1_1.Loanable.Title.TitleId,ur.UserId);
            Loan l1_2 = Helper.createLoanable(true).checkOut(u1);
            shiftToExpirationDate(l1_2);
            l1_2.save();
            Reservation.createReservation(l1_2.Loanable.Title.TitleId, ur.UserId);

            User u2 = Helper.createUserObject(false, true);
            Loan l2_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_1);
            l2_1.save();
            Reservation.createReservation(l2_1.Loanable.Title.TitleId, ur.UserId);
            Loan l2_2 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_2);
            l2_2.save();
            Reservation.createReservation(l2_2.Loanable.Title.TitleId, ur.UserId);
            Loan l2_3 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l2_3);
            l2_3.save();
            Reservation.createReservation(l2_3.Loanable.Title.TitleId, ur.UserId);

            User u3 = Helper.createUserObject(false, true);
            Loan l3_1 = Helper.createLoanable(true).checkOut(u2);
            shiftToExpirationDate(l3_1);
            l3_1.save();
            Reservation.createReservation(l3_1.Loanable.Title.TitleId, ur.UserId);

            Assert.AreEqual(6, Reservation.getReservationsByUser(ur.UserId).Count);

            Loan.handleExpiredLoans();

            Assert.AreEqual(6, Reservation.getReservationsByUser(ur.UserId).FindAll(l => l.LoanRecalled == true).Count);

            Assert.AreEqual(2, Notification.getAllForUser(u1.UserId).Count);
            //l1_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l1_1.ToBeReturnedDate, Loan.getLoan(l1_1.LoanId).ToBeReturnedDate);
            //l1_2.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l1_2.ToBeReturnedDate, Loan.getLoan(l1_2.LoanId).ToBeReturnedDate);

            Assert.AreEqual(3, Notification.getAllForUser(u2.UserId).Count);
            //l2_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_1.ToBeReturnedDate, Loan.getLoan(l2_1.LoanId).ToBeReturnedDate);
            //l2_2.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_2.ToBeReturnedDate, Loan.getLoan(l2_2.LoanId).ToBeReturnedDate);
            //l2_3.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l2_3.ToBeReturnedDate, Loan.getLoan(l2_3.LoanId).ToBeReturnedDate);

            Assert.AreEqual(1, Notification.getAllForUser(u3.UserId).Count);
            //l3_1.ToBeReturnedDate.AddDays(7);
            Assert.AreEqual(l3_1.ToBeReturnedDate, Loan.getLoan(l3_1.LoanId).ToBeReturnedDate);

        }


        private void shiftToExpirationDate(Loan l)
        {
            double shift = (l.ReturnDate - l.BorrowDate).TotalDays;
            l.ReturnDate.AddDays(-shift);
            l.BorrowDate.AddDays(-shift);
        }

    }
}
